package com.zk;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DelayQueue {

    private final transient ReentrantLock lock = new ReentrantLock();
    private final Condition available = lock.newCondition();

    private transient Item item = null;
    
    public boolean offer(Item e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            this.item = e;
            System.out.println("new item available: " + e);
            available.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }

    public Item take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                Item first = this.item;
                if (first == null) {
                    System.out.println("I am waiting...");
                    available.await();
                } else {
                    this.item = null;
                    return first;
                }
            }
        } finally {
            lock.unlock();
        }
    }
        
    static class Item {

        int value;

        public Item(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return String.valueOf(value);
        }
        
    }

    public static void main(String...args) {
        final DelayQueue delayQueue = new DelayQueue();
        
        for (int i=0; i<5; i++) {
            new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            delayQueue.take();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        for (int i=0; i<3; i++) {
            new Thread(new Runnable() {
                    @Override
                    public void run() {
                        delayQueue.offer(new Item(2));
                    }
                }).start();
        }
    }
    
}
